package ch.bfh.mobicomp.soda2.wifi.utils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;

import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.util.Log;

public class WifiApManager {
	
	private final WifiManager wifiManager;

	public WifiApManager(Context context) {
		wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
	}

	public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
		try {
			if (enabled) { // disable WiFi in any case
				wifiManager.setWifiEnabled(false);
			}

			Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
			
			return (Boolean) method.invoke(wifiManager, wifiConfig, enabled);
		} catch (Exception e) {
			Log.e(this.getClass().toString(), "", e);
			return false;
		}
	}
	
	public WIFI_AP_STATE getWifiApState() {
		try {
			Method method = wifiManager.getClass().getMethod("getWifiApState");

			int tmp = ((Integer) method.invoke(wifiManager));

			// Fix for Android 4
			if (tmp >= 10) {
				tmp = tmp - 10;
			}

			return WIFI_AP_STATE.class.getEnumConstants()[tmp];
		} catch (Exception e) {
			Log.e(this.getClass().toString(), "", e);
			return WIFI_AP_STATE.WIFI_AP_STATE_FAILED;
		}
	}
	
	public boolean isWifiApEnabled() {
		return getWifiApState() == WIFI_AP_STATE.WIFI_AP_STATE_ENABLED;
	}
	
	public WifiConfiguration getWifiApConfiguration() {
		try {
			Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");
			
			return (WifiConfiguration) method.invoke(wifiManager);
		} catch (Exception e) {
			Log.e(this.getClass().toString(), "", e);
			return null;
		}
	}
	
	public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
		try {
			Method method = wifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
			
			return (Boolean) method.invoke(wifiManager, wifiConfig);
		} catch (Exception e) {
			Log.e(this.getClass().toString(), "", e);
			
			return false;
		}
	}
	
	public ArrayList<ClientScanResult> getClientList(boolean onlyReachables) {
        return getClientList(onlyReachables, 300);
	}


    public ArrayList<ClientScanResult> getClientList(boolean onlyReachables, int reachableTimeout) {
            BufferedReader br = null;
            ArrayList<ClientScanResult> result = null;

            try {
                    result = new ArrayList<ClientScanResult>();
                    br = new BufferedReader(new FileReader("/proc/net/arp"));
                    String line;
                    while ((line = br.readLine()) != null) {
                            String[] splitted = line.split(" +");

                            if ((splitted != null) && (splitted.length >= 4)) {
                                    // Basic sanity check
                                    String mac = splitted[3];

                                    if (mac.matches("..:..:..:..:..:..")) {
                                            boolean isReachable = InetAddress.getByName(splitted[0]).isReachable(reachableTimeout);

                                            if (!onlyReachables || isReachable) {
                                                    result.add(new ClientScanResult(splitted[0], splitted[3], splitted[5], isReachable));
                                            }
                                    }
                            }
                    }
            } catch (Exception e) {
                    Log.e(this.getClass().toString(), e.getMessage());
            } finally {
                    try {
                            br.close();
                    } catch (IOException e) {
                            Log.e(this.getClass().toString(), e.getMessage());
                    }
            }

            return result;
    }
    
    public class ClientScanResult {
        private String IpAddr;

        private String HWAddr;

        private String Device;

        private boolean isReachable;

        public ClientScanResult(String ipAddr, String hWAddr, String device, boolean isReachable) {
                super();
                IpAddr = ipAddr;
                HWAddr = hWAddr;
                Device = device;
                this.setReachable(isReachable);
        }

        public String getIpAddr() {
                return IpAddr;
        }

        public void setIpAddr(String ipAddr) {
                IpAddr = ipAddr;
        }

        public String getHWAddr() {
                return HWAddr;
        }

        public void setHWAddr(String hWAddr) {
                HWAddr = hWAddr;
        }

        public String getDevice() {
                return Device;
        }

        public void setDevice(String device) {
                Device = device;
        }

        public void setReachable(boolean isReachable) {
                this.isReachable = isReachable;
        }

        public boolean isReachable() {
                return isReachable;
        }
    }
}
